<?php

namespace App\Console\Commands;

use App\Models\Topic;
use Elasticsearch\ClientBuilder;
use Illuminate\Console\Command;

class ElksearchTopics extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'elkSearch:topics {type?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'search topics';

    protected $client;

    protected $index;

    protected $type;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $hosts = explode(',', env('ELASTICSEARCH_HOST'));
        $this->client = ClientBuilder::create()->setHosts($hosts)->build();
        $this->index = config('elasticsearch.TOPIC')['index'];
        $this->type = config('elasticsearch.TOPIC')['type'];
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->info('start');
        $this->ini();
        $this->info('end');
    }

    public function ini($page = 0)
    {
        if ($this->argument('type') == 'delete') {
            $this->delIndex();
            return;
        }
        if (!$this->client->indices()->exists(['index' => $this->index])) {
            $this->createMapping();
        }
        $data = $this->getData($page);
        if (!empty($data)) {
            $params = ['body' => []];
            $i = 0;
            foreach ($data as $item) {
                if ($item['title']) {
                    $i++;
                    $params['body'][] = [
                        'index' => [
                            '_index' => $this->index,
                            '_type' => $this->type,
                            '_id' => $item['id']
                        ]
                    ];

                    $params['body'][] = $item;
                    if ($i % 500 == 0) {
                        $responses = $this->client->bulk($params);
                        $params = ['body' => []];
                        //节省内存
                        unset($responses);
                    }
                }
            }

            if (!empty($params['body'])) {
                $this->client->bulk($params);
            }
            unset($data, $params);
            $this->ini(++$page);
        }
    }

    public function getData($page)
    {
        $num = 500;
        $page = $page * $num;
        $topics = Topic::with('category', 'user')->skip($page)->take($num)->get();
        $data = [];
        foreach ($topics as $topic) {
            $tmp = [
                'id' => $topic->id,
                'title' => $topic->title,
                'body' => $topic->body,
                'excerpt' => $topic->excerpt,
                'categoryId' => $topic->category->id,
                'categoryName' => $topic->category->name,
                'userId' => $topic->user->id,
                'userName' => $topic->user->name,
                'createdAt' => $topic->created_at->timestamp
            ];
            $data[] = $tmp;
        }
        return $data;
    }

    public function createMapping()
    {
        $params = [
            'index' => $this->index,
            'body' => [
                'settings' => [
                    'number_of_shards' => 3, //设置主分片个数
                    'number_of_replicas' => 2, //设置复制分片个数
                    //自定义分析器
                    'analysis' => [
                        //预定义分词器--字符过滤器
                        'char_filter' => [
                            '&_to_and' => [
                                'type' => 'mapping',
                                'mappings' => ["&=>and"]
                            ]
                        ],
                        //'tokenizer' => [],
                        //预定义分词器--表征过滤器
                        'filter' => [
                            'my_stopwords' => [
                                'type' => 'stop',
                                'stopwords' => ['a', 'the', 'is']
                            ]
                        ],
                        //将预定义好的分词器和过滤器组合成我们的分析器
                        //type:keyword
                        'normalizer' => [
                            //自定义分析器
                            'reuters' => [
                                'type' => 'custom',
                                'char_filter' => ['&_to_and'],
                                'filter' => ['lowercase', 'asciifolding']
                            ]
                        ],
                        //type:text
                        'analyzer' => [
                            'reuters' => [
                                'type' => 'custom',
                                'char_filter' => ['html_strip', '&_to_and'],
                                'tokenizer' => "standard",
                                'filter' => ['lowercase', 'asciifolding', 'my_stopwords']
                            ]
                        ]
                    ]
                ],
                'mappings' => [
                    $this->type => [
                        '_source' => [
                            'enabled' => true
                        ],
                        'properties' => [
                            'id' => [
                                'type' => 'long'
                            ],
                            'title' => [
                                'type' => 'keyword',
                                'normalizer' => 'reuters'
                            ],
                            'body' => [
                                'type' => 'text',
                                'analyzer' => 'reuters'
                            ],
                            'excerpt' => [
                                'type' => 'text',
                                'analyzer' => 'reuters'
                            ],
                            'userId' => [
                                'type' => 'long'
                            ],
                            'userName' => [
                                'type' => 'text',
                                'analyzer' => 'reuters'
                            ],
                            'categoryId' => [
                                'type' => 'long'
                            ],
                            'categoryName' => [
                                'type' => 'keyword',
                                'normalizer' => 'reuters'
                            ],
                            'createdAt' => [
                                'type' => 'long'
                            ]
                        ]
                    ]
                ]
            ]
        ];
        $this->client->indices()->create($params);
    }

    public function delIndex()
    {
        if ($this->client->indices()->exists(['index' => $this->index])) {
            $params = ['index' => $this->index];
            $this->client->indices()->delete($params);
        }
    }
}
